package host.springboot.framework.context.filter;

import host.springboot.framework.context.ExecuteOrder;
import host.springboot.framework.context.filter.wrapper.RequestBodyWrapper;
import host.springboot.framework.context.util.HttpRequestUtils;
import lombok.Data;
import lombok.experimental.Accessors;
import org.jspecify.annotations.NonNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.servlet.filter.OrderedFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.function.Predicate;

/**
 * 请求体包装过滤器
 *
 * @author JiYinchuan
 * @since 1.0.0
 */
public class RequestBodyFilter implements OrderedFilter {

    private static final Logger LOGGER = LoggerFactory.getLogger(RequestBodyFilter.class);

    private static final String LOG_TAG = "KS-Filter-RequestBody";

    /**
     * 执行顺序
     *
     * <p>此处 {@link ExecuteOrder.Filter#REQUEST_BODY_WRAPPER} 必须为负数, 因为必须小于 {@value REQUEST_WRAPPER_FILTER_MAX_ORDER} 值
     */
    public static final int EXECUTE_ORDER = REQUEST_WRAPPER_FILTER_MAX_ORDER + ExecuteOrder.Filter.REQUEST_BODY_WRAPPER;

    /**
     * 执行条件
     */
    private final Predicate<HttpServletRequest> executePredicate;

    /**
     * 构造器
     *
     * @param config 配置
     * @since 1.0.0
     */
    public RequestBodyFilter(@NonNull Config config) {
        executePredicate = config.getExecutePredicate();
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        ServletRequest tmpServletRequest = servletRequest;
        if (servletRequest instanceof HttpServletRequest) {
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            if (executePredicate.test(request)) {
                tmpServletRequest = new RequestBodyWrapper(request);
                LOGGER.trace("[{}] The HttpServletRequest has been Wrapped.", LOG_TAG);
            }
        }
        filterChain.doFilter(tmpServletRequest, servletResponse);
    }

    @Override
    public int getOrder() {
        return EXECUTE_ORDER;
    }

    /**
     * 请求体包装过滤器配置
     *
     * @author JiYinchuan
     * @since 1.0.0
     */
    @Data
    @Accessors(chain = true)
    public static class Config {

        /**
         * 执行条件
         */
        private final Predicate<HttpServletRequest> executePredicate = HttpRequestUtils::isJsonRequest;

    }
}
